﻿using MSharp.Data.SPI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.Data;
using System.Data.Common;
using System.Reflection;
using System.Data.SqlClient;
using MySql.Data.MySqlClient;
using Oracle.ManagedDataAccess.Client;
using System.Configuration;
using System.Text.RegularExpressions;
using System.Data.SQLite;
using DDTek.Oracle;
using Npgsql;

namespace MSharp.Data
{
    public static partial class DBMgr
    {
        static DBMgr()
        {
            InitDLL();
        }
        static void InitDLL()
        {
            // 框架加载dll失败后执行，手动加载dll
            AppDomain.CurrentDomain.AssemblyResolve += (sender, senderArgs) =>
            {
                // 当前程序集
                var executingAssembly = Assembly.GetExecutingAssembly();
                // 当前程序集名称
                var assemblyName = new AssemblyName(executingAssembly.FullName).Name;
                // dll名称
                var dllName = new AssemblyName(senderArgs.Name).Name;
                // 待加载dll路径，指向当前程序集资源文件中dll路径。* 根据程序结构调整，使其正确指向dll
                var dllUri = assemblyName + "." + dllName + ".dll";
                // 加载dll
                using (var resourceStream = executingAssembly.GetManifestResourceStream(dllUri))
                {
                    var assemblyData = new Byte[resourceStream.Length];
                    resourceStream.Read(assemblyData, 0, assemblyData.Length);
                    return Assembly.Load(assemblyData); //加载dll
                }
            };
        }


        public static DB Connect(DBType dbType)
        {
            string connectionString = string.Empty;

            if (ConfigurationManager.ConnectionStrings[dbType.ToString()] != null)
            {
                connectionString = ConfigurationManager.ConnectionStrings[dbType.ToString()].ConnectionString;
            }
            else
            {
                throw new ArgumentNullException("connectionString", dbType.ToString() + "的connectionString不能为空！");
            }

            //处理 如果Sqlite 连接字符串只提供 路径的情况
            if (dbType == DBType.SQLite
                    && Regex.IsMatch(connectionString, @"^(\w):\\(.*)(.+\.db)$",
                    RegexOptions.IgnoreCase | RegexOptions.Compiled))
            {
                connectionString = string.Format("Data Source={0};Pooling=True;BinaryGUID=True;Enlist=N;Synchronous=Off;Journal Mode=WAL;Cache Size=5000;", connectionString);
            }

            return DBFactory.CreateInstance(dbType, connectionString);
        }

        public static DB Connect(DBType dbType, string connectionString)
        {
            //处理 如果Sqlite 连接字符串只提供 路径的情况
            if (dbType == DBType.SQLite
                    && Regex.IsMatch(connectionString, @"^(\w):\\(.*)(.+\.db)$",
                    RegexOptions.IgnoreCase | RegexOptions.Compiled))
            {
                connectionString = string.Format("Data Source={0};Pooling=True;BinaryGUID=True;Enlist=N;Synchronous=Off;Journal Mode=WAL;Cache Size=5000;", connectionString);
            }

            return DBFactory.CreateInstance(dbType, connectionString);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dbType">数据库类型</param>
        /// <param name="server">host地址</param>
        /// <param name="port">SqlServer默认端口：1433，MySql默认端口：3306，SqlServer默认端口：1433，Oracle默认端口：1521，PostgreSql默认端口：5432</param>
        /// <param name="databBase">数据库名称</param>
        /// <param name="uid">用户名</param>
        /// <param name="pwd">密码</param>
        /// <returns></returns>
        public static DB Connect(DBType dbType, string server, int? port, string databBase, string uid, string pwd)
        {
            return DBFactory.CreateInstance(dbType, GetConnectionString(dbType, server, port, databBase, uid, pwd));
        }

        /// <summary>
        /// 获取连接字符串
        /// </summary>
        /// <param name="dbType">数据库类型</param>
        /// <param name="server">host地址</param>
        /// <param name="port">SqlServer默认端口：1433，MySql默认端口：3306，SqlServer默认端口：1433，Oracle默认端口：1521，PostgreSql默认端口：5432</param>
        /// <param name="databBase">数据库名称</param>
        /// <param name="uid">用户名</param>
        /// <param name="pwd">密码</param>
        /// <returns></returns>
        public static String GetConnectionString(DBType dbType, string server, int? port, string databBase, string uid, string pwd)
        {
            server = (server ?? string.Empty).Trim();
            databBase = (databBase ?? string.Empty).Trim();
            uid = (uid ?? string.Empty).Trim();

            string connectionString = string.Empty;
            switch (dbType)
            {
                case DBType.SqlServer:
                    connectionString = string.Format(@"server={0},{1};database={2};uid={3};pwd={4}", server, (port ?? 1433), databBase, uid, pwd);
                    break;
                case DBType.MySql:
                    connectionString = string.Format(@"Server={0};port={1};Database={2};User={3};Password={4};", server, (port ?? 3306), databBase, uid, pwd);
                    break;
                case DBType.Oracle:
                    connectionString = string.Format("Data Source={0}:{1}/{2};User Id={3};password={4};Pooling=true;", server, (port ?? 1521), databBase, uid, pwd);
                    break;
                case DBType.OracleDDTek:
                    connectionString = string.Format("Host={0};Port={1};Service Name={2};User ID={3};Password={4};PERSIST SECURITY INFO=True;", server, (port ?? 1521), databBase, uid, pwd);
                    break;
                case DBType.PostgreSql:
                    connectionString = string.Format("host={0};port={1};database={2};user id={3};password={4};", server, (port ?? 5432), databBase, uid, pwd);
                    break;
                case DBType.SQLite:
                    connectionString = string.Format("Data Source={0};Pooling=True;BinaryGUID=True;Enlist=N;Synchronous=Off;Journal Mode=WAL;Cache Size=5000;", server);
                    break;
                default:
                    throw new ArgumentException("未知数据库类型！");
            }
            return connectionString;
        }

        /// <summary>
        /// 获取数据类型对应的 DbProviderFactory
        /// </summary>
        /// <param name="dbType">数据库类型</param>
        /// <returns></returns>
        public static DbProviderFactory GetProviderFactory(DBType dbType)
        {
            switch (dbType)
            {
                case DBType.SqlServer:
                    return SqlClientFactory.Instance;
                case DBType.MySql:
                    return MySqlClientFactory.Instance;
                case DBType.Oracle:
                    return OracleClientFactory.Instance;
                case DBType.OracleDDTek:
                    return OracleFactory.Instance;
                case DBType.PostgreSql:
                    return NpgsqlFactory.Instance;
                case DBType.SQLite:
                    return SQLiteFactory.Instance;
                default:
                    throw new ArgumentException("未支持的数据库类型！");
            }
        }

    }
}
